package ydsy;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Frame
    extends JFrame {
  JTextField text;
  JLabel nowBomb, setBomb;
  int BombNum, BlockNum; //当前雷数，当前方块数
  int rightBomb, restBomb, restBlock; //找到的地雷数，剩余雷数，剩余方块数

  JButton start = new JButton(" 开始 ");//初始化一个开始的按钮
  JPanel MenuPanel = new JPanel();//新建一个区域，作为菜单
  JPanel bombPanel = new JPanel();//新建一个区域，作为雷区
  Bomb[][] bombButton;//2维数组，防地雷

  JPanel c;
  BorderLayout borderLayout1 = new BorderLayout();//布局管理器边界布局
  GridLayout gridLayout1 = new GridLayout();//布局一个网格布局
  public Frame() {
    try {
      setDefaultCloseOperation(EXIT_ON_CLOSE);//关闭操作并结束进程
      jbInit();//一般用于对程序进行初始化
    }
    catch (Exception exception) {//异常处理
      exception.printStackTrace();
    }
  }

private void jbInit() throws Exception {
    c = (JPanel) getContentPane();//设定一个空间
    setTitle("扫雷");//标题为扫雷
    c.setBackground(Color.WHITE);//背景颜色为白色
    MenuPanel.setBackground(Color.GRAY);//菜单颜色为灰色
    c.setLayout(borderLayout1);
    setSize(new Dimension(700, 700));//界面大小700*700
    setResizable(false);

    BlockNum = 144;//设定方块数144个
    BombNum = 10;//设定初始地雷数10个
    text = new JTextField("10 ", 3);//设定一个字符框长度为3
    nowBomb = new JLabel("当前雷数" + ":" + BombNum);
    setBomb = new JLabel("设置地雷数");//标明解释
    start.addActionListener(new Frame1_start_actionAdapter(this));

    MenuPanel.add(setBomb);
    MenuPanel.add(text);
    MenuPanel.add(start);
    MenuPanel.add(nowBomb);//添加菜单元素
    c.add(MenuPanel, java.awt.BorderLayout.SOUTH);//给界面下方的界面设定布局

    bombPanel.setLayout(gridLayout1);
    gridLayout1.setColumns( (int) Math.sqrt(BlockNum));//纵列设定
    gridLayout1.setRows( (int) Math.sqrt(BlockNum));//横排设定
    bombButton = new Bomb[ (int) Math.sqrt(BlockNum)][ (int) Math.sqrt(BlockNum)];
    for (int i = 0; i < (int) Math.sqrt(BlockNum); i++) {
      for (int j = 0; j < (int) Math.sqrt(BlockNum); j++) {//嵌套for循环表示所有的格子
        bombButton[i][j] = new Bomb(i, j);
        
        bombButton[i][j].setFont(new Font("", Font.PLAIN, 14));//设计字体显示效果
      
        bombButton[i][j].setForeground(Color.white);//背景颜色为白色
        bombButton[i][j].addMouseListener(new Bomb_mouseAdapter(this));
        bombButton[i][j].addActionListener(new Bomb_actionAdapter(this));
        bombPanel.add(bombButton[i][j]);
      }
    }
    c.add(bombPanel, java.awt.BorderLayout.CENTER);//给界面中间的界面设定布局

    startBomb();
  }

/* 开始按钮 */

  public void start_actionPerformed(ActionEvent e) {
   int num=Integer.parseInt(text.getText().trim());//调用Integer.parseInt()把一个String转换成一个Double基本类型的值并赋值给了num
    if (num >= 5 && num < 50) {
      BombNum = num;//如果当前雷数在5-50之间
      startBomb();//可以开始布雷。
    }
    else if (num < 5) {//如果当前雷数在5以下
      JOptionPane.showMessageDialog(null, "您设置的地雷数太少了,请重设!", "错误",
                                    JOptionPane.ERROR_MESSAGE);//消息提示框显示错误。
                                    num=10;
                                    BombNum = num;//自动将雷数改为10.
    }
    else {
      JOptionPane.showMessageDialog(null, "您设置的地雷数太多了,请重设!", "错误",
                                    JOptionPane.ERROR_MESSAGE);//同上，消息提示框提醒输入有误。
                                     num=10;
                                    BombNum = num;
    }
  }
  /* 开始,布雷 */
  

  public void startBomb() {
    nowBomb.setText("当前雷数" + "：" + BombNum);//利用setText设置现在的雷数。
    for (int i = 0; i < (int) Math.sqrt(BlockNum); i++) {//由按钮组成的二维数组，i表示行，j表示列，构成了一个方形网格
      for (int j = 0; j < (int) Math.sqrt(BlockNum); j++) {//循环条件判断isRight的值，如果为false循环否则退出
        bombButton[i][j].isBomb = false;//当前按钮是否为雷
        bombButton[i][j].isClicked = false;//是否已被点击
        bombButton[i][j].isRight = false;//是否被(标注)正确
        bombButton[i][j].BombFlag = 0;//是否被标注为雷
        bombButton[i][j].BombRoundCount = 9;//周围
        bombButton[i][j].setEnabled(true);
        bombButton[i][j].setText("");
        bombButton[i][j].setFont(new Font("", Font.PLAIN, 14));//设置字体大小
        bombButton[i][j].setForeground(Color.BLUE);//设置颜色为蓝色
        rightBomb = 0;//正确标出的雷数为0
        restBomb = BombNum;
        restBlock = BlockNum - BombNum;
      }
    }

    for (int i = 0; i < BombNum; ) {
      int x = (int) (Math.random() * (int) (Math.sqrt(BlockNum) - 1));
      int y = (int) (Math.random() * (int) (Math.sqrt(BlockNum) - 1));

      if (bombButton[x][y].isBomb != true) {
        bombButton[x][y].isBomb = true;
        i++;
      }
    }
    CountRoundBomb();
  }

  /* 计算方块周围雷数 */

  public void CountRoundBomb() {
    for (int i = 0; i < (int) Math.sqrt(BlockNum); i++) {//开方 障碍数
      for (int j = 0; j < (int) Math.sqrt(BlockNum); j++) {
        int count = 0;//当需要检测的单元格本身无雷的情况下，统计周围的地雷个数
        
        if (bombButton[i][j].isBomb != true) {//如果不是雷
          for (int x = i - 1; x < i + 2; x++) {//从左边到右，一个三个
            for (int y = j - 1; y < j + 2; y++) {
              if ( (x >= 0) && (y >= 0)
                  && (x < ( (int) Math.sqrt(BlockNum)))
                  && (y < ( (int) Math.sqrt(BlockNum)))) {//因前面x=i-1，所以排除超出边界的情况
                if (bombButton[x][y].isBomb == true) {//如果是雷
                  count++;//加一
                }
              }
            }
          }
          bombButton[i][j].BombRoundCount = count;//设置该Bomb环绕数的值
        }
      }
    }
  }

  /* 是否挖完了所有的雷 */

  public void isWin() {
    restBlock = BlockNum - BombNum;//剩余方块数等于方块数减去雷数
    for (int i = 0; i < (int) Math.sqrt(BlockNum); i++) {
      for (int j = 0; j < (int) Math.sqrt(BlockNum); j++) {
        if (bombButton[i][j].isClicked == true) {//如果点击正确，剩余方块数减一
          restBlock--;
        }
      }
    }

    if (rightBomb == BombNum || restBlock == 0) {//如果地雷数目或者剩余方块数为0
      JOptionPane.showMessageDialog(this, "您挖完了所有的雷，您胜利了!", "胜利",
                                    JOptionPane.INFORMATION_MESSAGE);
      startBomb();
    }
  }

  /** 当选中的位置为空,则翻开周围的地图* */

  public void isNull(Bomb ClickedButton) {
    int i, j;
    i = ClickedButton.num_x;
    j = ClickedButton.num_y;//设定自动点击的方块

    for (int x = i - 1; x < i + 2; x++) {
      for (int y = j - 1; y < j + 2; y++) {
        if ( ( (x != i) || (y != j)) && (x >= 0) && (y >= 0)
            && (x < ( (int) Math.sqrt(BlockNum)))
            && (y < ( (int) Math.sqrt(BlockNum)))) {
          if (bombButton[x][y].isBomb == false
              && bombButton[x][y].isClicked == false
              && bombButton[x][y].isRight == false) {
            turn(bombButton[x][y]);//自动选择周围的格子
          }
        }
      }
    }
  }

  /* 翻开 */

  public void turn(Bomb ClickedButton) {
    ClickedButton.setEnabled(false);
    ClickedButton.isClicked = true;
    if (ClickedButton.BombRoundCount > 0) {
      ClickedButton.setText(ClickedButton.BombRoundCount + "");
    }
    else {
      isNull(ClickedButton);
    }
  }

  
  /* 左键点击 */
  public void actionPerformed(ActionEvent e) {
    if ( ( (Bomb) e.getSource()).isClicked == false
        && ( (Bomb) e.getSource()).isRight == false) {
      if ( ( (Bomb) e.getSource()).isBomb == false) {
        turn( ( (Bomb) e.getSource()));
        isWin();//点击正确的格子
      }

      else {
        for (int i = 0; i < (int) Math.sqrt(BlockNum); i++) {
          for (int j = 0; j < (int) Math.sqrt(BlockNum); j++) {
            if (bombButton[i][j].isBomb == true) {
              bombButton[i][j].setText("b");//在是地雷的方格上标记b
            }
          }
        }
        ( (Bomb) e.getSource()).setForeground(Color.RED);
        ( (Bomb) e.getSource()).setFont(new Font("", Font.BOLD, 20));//设置地雷格子的字体
        ( (Bomb) e.getSource()).setText("X");//在踩中的地雷格子上标记文字X
        JOptionPane.showMessageDialog(this, "你踩到地雷了，按确定重来", "踩到地雷", 2);//踩中格子后弹出文字提示框
        startBomb();
      }
    }
  }

 
  /* 右键点击 */
  public void mouseClicked(MouseEvent e) {
    Bomb bombSource = (Bomb) e.getSource();
    boolean right = SwingUtilities.isRightMouseButton(e);//boolean型变量

    if ( (right == true) && (bombSource.isClicked == false)) {
      bombSource.BombFlag = (bombSource.BombFlag + 1) % 3;
      if (bombSource.BombFlag == 1) {//将鼠标点击次数+1除以3等于1的格子标记为F
        if (restBomb > 0) {
          bombSource.setForeground(Color.RED);
          bombSource.setText("F");//在被鼠标右键标记的格子上标记文字F
          bombSource.isRight = true;//标记后剩余地雷自动减一
          restBomb--;
        }
        else {
          bombSource.BombFlag = 0;
        }
      }
      else if (bombSource.BombFlag == 2) {//将点击次数加1除以3等于2的格子标记为Q
        restBomb++;
        bombSource.setText("Q");
        bombSource.isRight = false;
      }
      else {//否则什么都不标记
        bombSource.setText("");
      }

      if (bombSource.isBomb == true) {
        if (bombSource.BombFlag == 1) {//为F的情况下正确的雷数加一
          rightBomb++;
        }
        else if (bombSource.BombFlag == 2) {//为Q的情况下正确的雷数不变
          rightBomb--;
        }
      }
      nowBomb.setText("当前雷数" + ":" + restBomb);
      isWin();//最终弹出文字框显示当前雷数和剩余雷数
    }
  }

  public static void main(String[] args) {
    Frame frame = new Frame();
    frame.setVisible(true);
  }
}

class Frame1_start_actionAdapter
    implements ActionListener {
  private Frame adaptee;
  Frame1_start_actionAdapter(Frame adaptee) {
    this.adaptee = adaptee;
  }//构造初始化成员

  public void actionPerformed(ActionEvent e) {
    adaptee.start_actionPerformed(e);
  }
}

////////////////////////////
class Bomb
    extends JButton {
  int num_x, num_y; //第几号方块
  int BombRoundCount; //周围雷数
  boolean isBomb; //是否为雷
  boolean isClicked; //是否被点击
  int BombFlag; //测试雷标记
  boolean isRight; //是否点击右键

  public Bomb(int x, int y) {
    num_x = x;
    num_y = y;//雷的位置，获得是参数值，嵌套了两个for循环
    BombFlag = 0;//是否已经插旗了
    BombRoundCount = 9;//环绕数
    isBomb = false;//是雷
    isClicked = false;//被点击
    isRight = false;//是真的
  }
}

class Bomb_actionAdapter
    implements ActionListener {
  private Frame adaptee;
  Bomb_actionAdapter(Frame adaptee) {
    this.adaptee = adaptee;
  }//设定Frame adaptee接口

  public void actionPerformed(ActionEvent e) {
    adaptee.actionPerformed(e);
  }
}

class Bomb_mouseAdapter
    extends MouseAdapter {
  private Frame adaptee;
  Bomb_mouseAdapter(Frame adaptee) {
    this.adaptee = adaptee;
  }//设定mouseAdapter接口

  public void mouseClicked(MouseEvent e) {
    adaptee.mouseClicked(e);
  }
}